using System;
using System.Collections.Generic;

namespace AK.Wwise.Editor
{
	public abstract class BaseTypeDrawer : UnityEditor.PropertyDrawer
	{
		public override void OnGUI(UnityEngine.Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label)
		{
			UnityEditor.EditorGUI.BeginProperty(position, label, property);

            UnityEditor.SerializedProperty name = property.FindPropertyRelative("Name");
            var componentName = name.stringValue;
            UnityEditor.SerializedProperty vguid = property.FindPropertyRelative("valueGuid.Array");
            var guid = AkUtilities.GetByteArrayProperty(vguid);

            WwiseObjectReference wof = null;
            if (componentName == string.Empty && guid != null)
            {
                if (WwiseObjectType == WwiseObjectType.Event)
                {
                    AkWwiseProjectData.Event tmp = AudioStudio.AudioUtility.FindEvent(new System.Guid(guid));
                    if (tmp != null)
                        componentName = tmp.Name;
                }
                else if (WwiseObjectType == WwiseObjectType.State)
                {
                    var StateWwu = AkWwiseProjectInfo.GetData().StateWwu;
                    Guid gg = new Guid(guid);

                    for (int i = 0; i < StateWwu.Count; i++)
                    {
                        for (int j = 0; j < StateWwu[i].List.Count; j++)
                        {
                            var e = StateWwu[i].List[j].values.Find(x => x.Guid.Equals(gg));
                            if (e != null)
                            {
                                componentName = e.Name;
                                break;
                            }
                        }
                    }
                }
            }
            if (componentName != string.Empty && guid != null)
                wof = WwiseObjectReference.FindOrCreateWwiseObject(WwiseObjectType, componentName, new System.Guid(guid));
            HandleDragAndDrop(ref wof, position);
            if (wof != null)
            {
                AcceptDragDrop(property, wof);
            }

            position = UnityEditor.EditorGUI.PrefixLabel(position,
				UnityEngine.GUIUtility.GetControlID(UnityEngine.FocusType.Passive), label);

			var style = new UnityEngine.GUIStyle(UnityEngine.GUI.skin.button);
			style.alignment = UnityEngine.TextAnchor.MiddleLeft;
			style.fontStyle = UnityEngine.FontStyle.Normal;
            
			if (string.IsNullOrEmpty(componentName))
			{
				componentName = "No " + WwiseObjectType + " is currently selected";
				style.normal.textColor = UnityEngine.Color.red;
			}

			if (UnityEngine.GUI.Button(position, componentName, style))
			{
                new AkWwiseComponentPicker.PickerCreator
                {
                    objectType = WwiseObjectType,
                    wwiseObjectReference = property,
                    pickerPosition = AkUtilities.GetLastRectAbsolute(position),
                    serializedObject = property.serializedObject,
                    onPickerChanged = (UnityEditor.SerializedProperty p, TreeView.TreeViewItem treeItem) =>
                    {
                        OnPickerChanged(p, treeItem);
                    }
				};
			}

			UnityEditor.EditorGUI.EndProperty();
		}

		protected abstract WwiseObjectType WwiseObjectType { get; }

		protected virtual string GetComponentName(UnityEditor.SerializedProperty wwiseObjectReference)
		{
			var reference = wwiseObjectReference.objectReferenceValue as WwiseObjectReference;
			return reference ? reference.DisplayName : string.Empty;
		}

		private void HandleDragAndDrop(ref WwiseObjectReference wwiseObjectReference, UnityEngine.Rect dropArea)
		{
			var currentEvent = UnityEngine.Event.current;

			if (currentEvent.type == UnityEngine.EventType.DragExited)
			{
				UnityEditor.DragAndDrop.PrepareStartDrag();
			}
			else if ((currentEvent.type == UnityEngine.EventType.DragUpdated || currentEvent.type == UnityEngine.EventType.DragPerform)
				&& dropArea.Contains(currentEvent.mousePosition))
			{
				var reference = UnityEditor.DragAndDrop.GetGenericData(AkDragDropHelper.DragDropIdentifier) as WwiseObjectReference;
				if (reference != null && reference.WwiseObjectType != WwiseObjectType)
					reference = null;

				if (currentEvent.type == UnityEngine.EventType.DragUpdated)
				{
					UnityEditor.DragAndDrop.visualMode = reference != null
						? UnityEditor.DragAndDropVisualMode.Link
						: UnityEditor.DragAndDropVisualMode.Rejected;
				}
				else
				{
					UnityEditor.DragAndDrop.AcceptDrag();

                    if (reference != null)
                    {
                        wwiseObjectReference = reference;
                    }

					UnityEngine.GUIUtility.hotControl = 0;
				}

				currentEvent.Use();
			}
		}

        protected virtual void OnPickerChanged(UnityEditor.SerializedProperty property, TreeView.TreeViewItem treeItem)
        {

        }

        protected void PickerChangeGroup(UnityEditor.SerializedProperty property, TreeView.TreeViewItem treeItem, List<AkWwiseProjectData.GroupValWorkUnit> list)
        {
            var guidProperty = property.FindPropertyRelative("valueGuid.Array");
            Guid guid = Guid.Empty;
            if (treeItem != null)
            {
                guid = new Guid((treeItem.DataContext as AkWwiseTreeView.AkTreeInfo).Guid.ToByteArray());
            }
            Guid groupGuid = Guid.Empty;
            if (treeItem != null && treeItem.Parent != null)
            {
                groupGuid = new Guid((treeItem.Parent.DataContext as AkWwiseTreeView.AkTreeInfo).Guid.ToByteArray());
            }
            AkUtilities.SetByteArrayProperty(guidProperty, guid.ToByteArray());
            for (int i = 0; i < list.Count; i++)
            {
                var group = list[i].List.Find(x => x.Guid.Equals(groupGuid));

                if (group != null)
                {
                    int index = group.values.FindIndex(x => x.Guid.Equals(guid));

                    if (index < 0)
                        break;

                    property.FindPropertyRelative("Id").longValue = group.values[index].Id;
                    property.FindPropertyRelative("Name").stringValue = group.values[index].Name;
                    if (property.FindPropertyRelative("GroupId") != null)
                        property.FindPropertyRelative("GroupId").longValue = group.Id;
                    if (property.FindPropertyRelative("GroupName") != null)
                        property.FindPropertyRelative("GroupName").stringValue = group.Name;
                    return;
                }
            }

            property.FindPropertyRelative("Id").longValue = 0;
            property.FindPropertyRelative("Name").stringValue = string.Empty;
            if (property.FindPropertyRelative("GroupId") != null)
                property.FindPropertyRelative("GroupId").longValue = 0;
            if (property.FindPropertyRelative("GroupName") != null)
                property.FindPropertyRelative("GroupName").stringValue = string.Empty;
        }

        protected void PickerChanged(UnityEditor.SerializedProperty property, TreeView.TreeViewItem treeItem)
        {
            Guid guid = Guid.Empty;
            if (treeItem != null)
            {
                guid = new Guid((treeItem.DataContext as AkWwiseTreeView.AkTreeInfo).Guid.ToByteArray());
            }
            var guidProperty = property.FindPropertyRelative("valueGuid.Array");
            AkUtilities.SetByteArrayProperty(guidProperty, guid.ToByteArray());
            if (guid != Guid.Empty)
            {
                string name = treeItem.Header;
                uint Id = AkUtilities.ShortIDGenerator.Compute(name);

                property.FindPropertyRelative("Id").longValue = Id;
                property.FindPropertyRelative("Name").stringValue = name;
            }
            else
            {
                property.FindPropertyRelative("Id").longValue = 0;
                property.FindPropertyRelative("Name").stringValue = string.Empty;
            }
        }

        protected virtual void AcceptDragDrop(UnityEditor.SerializedProperty property, WwiseObjectReference wof)
        {
            property.FindPropertyRelative("Id").longValue = wof.Id;
            property.FindPropertyRelative("Name").stringValue = wof.ObjectName;
            AkUtilities.SetByteArrayProperty(property.FindPropertyRelative("valueGuid.Array"), wof.Guid.ToByteArray());
            var groupReference = wof as WwiseGroupValueObjectReference;
            if (groupReference != null && groupReference.GroupObjectReference != null)
            {
                if (property.FindPropertyRelative("GroupId") != null)
                    property.FindPropertyRelative("GroupId").longValue = groupReference.GroupObjectReference.Id;
                if (property.FindPropertyRelative("GroupName") != null)
                    property.FindPropertyRelative("GroupName").stringValue = groupReference.GroupObjectReference.DisplayName;
            }
        }
    }
}
